﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;

namespace Client_Server_Interface
{
    //public class Interfaces
    //{

    public delegate void VoidDelegate();

    public delegate void VoidBoolDelegate(bool a);

    public delegate void VoidIntDelegate(int a);

    /// <summary>
    /// Делегат для реакции на сообщения об ошибках с приборов.
    /// </summary>
    /// <param name="device">Информация о приборе.</param>
    /// <param name="newRecords">Список текущих ошибок наприборе.</param>
    /// <param name="unreadCount">Количество непрочтенных сообщений с прибора.</param>
    /// <param name="totalUnreadCount">Общее количество непрочтенных сообщений со всех приборов.</param>
    public delegate void NewErrorRecordDelegate(DeviceTreeItem.DeviceInfo device, ObservableCollection<ErrorListRecord> newRecords, int unreadCount, int totalUnreadCount);

    /// <summary>
    /// Возможные типы запросов клиента.
    /// </summary>
    public class ClientRequestTypes
    {
        public const string CLIENT_LOGIN_REQUEST = "login";
        public const string CLIENT_LOGS_REQUEST = "devlogdata";
        public const string CLIENT_DEVICE_TREE_REQUEST = "device_tree";
        public const string CLIENT_LOGIN_PERMISSIONS_REQUEST = "permissions";
    }

    /// <summary>
    /// Возможные ответа сервера на заросы.
    /// </summary>
    public class ServerResponceTypes
    {
        public const string ERROR = "err:";
        public const string ACCESS_DENIED = "accessden:";
        public const string ACCESS_GRANTED = "accessgranted:";
        public const string INNER_ERROR = "innererror";
        public const string NOT_IMPLEMENTED_REQUEST = "notimpl";
        public const string NOT_AUTHORIZED = "nt_thrzd";
        public const string WRONG_REQUEST_STRING = "wrongstring";
        public const string LOGIN_IS_NOT_UNIQUE = "not_unique_login";
        public const string WRONG_VERSION = "version";
        public const string CONNECTIONS_LIMIT = "connections_limit";
        public const string WRONG_LOGIN = "login";
        public const string UNKNOWN_ADDRESS = "unknownaddress";
        public const string UNKNOWN_CLIENT_ID = "unknown_client_id";
    }

    /// <summary>
    /// Сообщения исключений, происходящих во время работы клиента.
    /// </summary>
    public class ClientExceptionMessage
    {
        public const string CONNECTION_IS_NOT_ESTABLISHED = "No_connection_with_server";
        public const string CONNECTION_ALREADY_ESTABLISHED = "Already_connected";
        public const string CAN_NOT_CONNECT_TO_THE_SERVER = "Can_not_connect_to_the_server";
        public const string COORDINATES_WRONG_STRING = "Incorrect_coordinates";
        public const string INCORRECT_IP_ADDRESS = "Incorrent_ip";
        public const string INCORRECT_SUBITEM_ADDED = "Wrong_subitem_added";
        public const string INVALID_TREE_RECEIVED = "TreeIsNotValid";
        public const string DEVICE_TREE_IS_NOT_INITIALIZED = "DeviceTreeIsNotInitialized";
        public const string FILE_IS_NOT_EXIST = "FileIsNotExist";
        public const string NOT_INITIALIZED = "NotInitialized";
        public const string ALREADY_STARTED = "AlreadyStarted";
        public const string UNKNOWN_SERVER_RESPONSE = "UnknownServerResponse";
        public const string GET_LOG_ERROR = "GetLogError";
        public const string EMPTY = "empty";
        public const string LIBRARY_INITIALIZATION_ERROR = "LibError";
    }

    public class DeviceResponce
    {
        public const string ERROR = "err";
        public const string ALARM = "alarm";
        public const string INFO = "info";
        public const string WARNING = "warning";
    }

    public interface IMonitoringClient
    {
        void Connect(VoidDelegate onDisconnect, IPAddress serverIp, int serverPort);

        StringBuilder GetLogFromServer(string regions, string blrs, string stations, string deviceTypes,
                                DateTime startTime, DateTime endTime);

        byte[] LoginToServer(string login, string password, byte[] clientId, string clientVersion);

        DeviceTree LoginToServer_GetTree(string login, string password, byte[] clientId, string clientVersion);
    }

    public interface IMonitoringDeviceWorker
    {
        void Initialize(List<IDeviceInterface> devices, NewErrorRecordDelegate newErrorRecordReaction, string requestPeriod);
        void Start();
        void Stop();
        /// <summary>
        /// Устанавливает значение "Просматривается состояние" для прибора.
        /// </summary>
        /// <param name="deviceInfo"></param>
        /// <param name="opened"></param>
        void ChangeDeviceOpenedState(DeviceTreeItem.DeviceInfo deviceInfo, bool opened);
    }

    /// <summary>
    /// Интерфейс для 
    /// </summary>
    public interface IDeviceInterface
    {
        /// <summary>
        /// Метод должен использоваться для получения данных с устройства и подготовки ErrorsList.
        /// </summary>
        /// <param name="ct">Токен отмены для метода.</param>
        void Action(CancellationToken ct);
        /// <summary>
        /// Установка устройству флага для определения, нужно ли оповещать о непрочитанных сообщениях.
        /// </summary>
        bool Opened { set; }
        /// <summary>
        /// Говорит всем устройствам, что все их списки ошибок просматриваются в данный момент.
        /// </summary>
        bool AllOpened { get; set; }

        int UnreadCount { get; set; }

        /// <summary>
        /// Тут все ясно.
        /// </summary>
        event EventHandler ErrorsListChanged;

        /// <summary>
        /// Информация об устройстве.
        /// </summary>
        DeviceTreeItem.DeviceInfo DevInfo { get; set; }
        /// <summary>
        /// Список ошибок на устройстве, который генерируется методом Action.
        /// </summary>
        ObservableCollection<ErrorListRecord> ErrorsList { get; set; }
        /// <summary>
        /// Общее количество непрочитанных сообщений с приборов. Должен быть static.
        /// </summary>
        int TotalUnreadRecordsCount { get;}
    }

    public abstract class DeviceBlank : IDeviceInterface
    {
        public DeviceTreeItem.DeviceInfo DevInfo { get; set; }
        public ObservableCollection<ErrorListRecord> ErrorsList { get; set; }
        protected static NewErrorRecordDelegate OnErrorAppear;
        protected GetStatusDelegate GetStatus;
        public delegate string GetStatusDelegate();
        public event EventHandler ErrorsListChanged;

        protected virtual void OnErrorsListChanged()
        {
            EventHandler handler = ErrorsListChanged;
            if (handler != null) handler(this, EventArgs.Empty);
        }

        int IDeviceInterface.TotalUnreadRecordsCount
        {
            get { return TotalUnreadRecordsCount; }
        }

        public static int TotalUnreadRecordsCount { get; set; }

        public static bool AllOpened;
        bool IDeviceInterface.AllOpened
        {
            get { return AllOpened; }
            set
            {
                if (value)
                    TotalUnreadRecordsCount = 0;
                AllOpened = value;
            }
        }
        private bool _opened;
        public bool Opened
        {
            set
            {
                if (value)
                {
                    TotalUnreadRecordsCount -= UnreadCount;
                    UnreadCount = 0;
                }
                _opened = value;
            }
            protected get { return _opened; }
        }

        public int UnreadCount { get; set; }

        public override int GetHashCode()
        {
            return DevInfo.GetHashCode();
        }

        public abstract void Action(CancellationToken ct);

        protected abstract void CreateErrorsList(string status);
    }

    public interface IMonitoringClientDBwork
    {
        bool SetParameter(string paramName, string paramValue);
        string GetParameterValue(string paramName);
        Dictionary<string, string> GetParametersList();

        void SetLibraryName(string deviceName, string libraryName);
        string GetLibraryName(string deviceName);

        void SetTreeItemTag(string itemName, string tag);
        string GetTreeItemTag(string itemName);

        void SetMapMarkerPosition(string markerName, double lat, double lng);
        KeyValuePair<double, double> GetMapMarkerPosition(string markerName);

    }

    //}
}
